import json
from time import sleep
from _thread import start_new_thread

import pytest

import server


class TestSock:
    def __init__(self):
        self.messages_to_recv: list = []
        self.sended_messages: dict = {}

    def addmsg(self, msg, addr):
        self.messages_to_recv.append((msg, addr))

    def lastsended(self, addr):
        return self.sended_messages[addr].pop(-1)

    def recvfrom(self, *args, **kwargs):
        while 1:
            if len(self.messages_to_recv) > 0:
                msg, addr = self.messages_to_recv.pop(0)
                return json.dumps(msg).encode("ascii"), addr
            sleep(0.05)

    def sendto(self, rawdata: bytes, addr):
        if addr not in self.sended_messages:
            self.sended_messages[addr] = []
        self.sended_messages[addr].append(json.loads(rawdata.decode("ascii")))


sock = TestSock()


@pytest.fixture(autouse=True)
def run_server():
    server.AFK_TIME = 2
    server.MAX_PLAYERS = 4
    server.sock = sock

    start_new_thread(server.delete_afk_players, ())
    start_new_thread(server.recv_and_send, ())


def test_all():
    tester1_addr = ("12.15.11.50", 1150)
    tester2_addr = ("15.12.11.50", 1150)
    tester3_addr = ("15.12.11.50", 1818)
    tester4_addr = ("15.12.11.70", 1818)
    tester5_addr = ("15.15.11.70", 1218)

    sock.addmsg({}, tester1_addr)
    sleep(0.2)
    assert sock.lastsended(tester1_addr) == {"error": "no 'name' in data"}

    sock.addmsg({"name": "tester1", "x": 12}, tester1_addr)
    sleep(0.2)
    assert tester1_addr in server.players
    assert tester1_addr in sock.sended_messages
    assert sock.lastsended(tester1_addr) == [{"name": "tester1", "x": 12}]

    sock.addmsg({"name": "tester1"}, tester2_addr)
    sleep(0.2)
    assert sock.lastsended(tester2_addr) == {
        "error": "player with name='tester1' already in game."
    }

    sock.addmsg({"name": "tester2"}, tester2_addr)
    sleep(0.2)
    assert sock.lastsended(tester2_addr) == [
        {"name": "tester1", "x": 12},
        {"name": "tester2"},
    ]

    sock.addmsg({"name": "tester3"}, tester3_addr)
    sock.addmsg({"name": "tester4", "y": 11}, tester4_addr)
    sleep(0.2)
    assert sock.lastsended(tester4_addr) == [
        {"name": "tester1", "x": 12},
        {"name": "tester2"},
        {"name": "tester3"},
        {"name": "tester4", "y": 11},
    ]

    sock.addmsg({"name": "tester5"}, tester5_addr)
    sleep(0.2)
    assert sock.lastsended(tester5_addr) == {
        "error": "players limit reached. players limit: 4"
    }

    sleep(2)
    sock.addmsg({"name": "tester5"}, tester5_addr)
    sleep(0.2)
    assert sock.lastsended(tester5_addr) == [{"name": "tester5"}]

    sock.addmsg({"delete": 1}, tester5_addr)
    sleep(0.2)
    assert server.players == {}
